package com.wzx.common.core.controller;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.wzx.common.pojo.req.PageRequestDto;
import com.wzx.common.pojo.resp.Result;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

/**
 * @author wzx
 * @version 1.0
 * @date 2022/1/24 - 11:12
 * @description 核心controller，将一些公共controller代码抽取
 */
@Slf4j
public abstract class AbstractCoreController<T> implements ICoreController<T> {
    /**
     * 调用方的service
     */
    protected IService<T> coreService;

    protected AbstractCoreController(IService<T> coreService) {
        this.coreService = coreService;
    }


    /**
     * 1，新增记录
     *
     * @param record 新增对象
     * @return
     */
    @Override
    @PostMapping("/insert")
    @ApiOperation(value = "添加信息")
    public Result insert(@RequestBody T record) {
        log.info(record.toString());
        boolean flag = coreService.save(record);
        if (!flag) {
            log.error("新增数据{}，失败！！！", record);
            return Result.error("新增数据失败！！！");
        }
        log.info("新增记录：{}成功！", record);
        return Result.ok();
    }

    /**
     * 2，删除记录
     *
     * @param id
     * @return
     */
    @Override
    @DeleteMapping("/deleteById/{id}")
    @ApiOperation(value = "根据id删除")
    public Result deleteById(@PathVariable(name = "id") Serializable id) {
        boolean flag = coreService.removeById(id);
        if (!flag) {
            log.error("根据id{}删除记录错误失败！！！", id);
            return Result.error("删除记录失败！！！");
        }
        log.info("删除id为：{}的记录成功！", id);
        return Result.ok();
    }

    /**
     * 3，更新记录
     *
     * @param record
     * @return
     */
    @Override
    @PutMapping("/updateByPrimaryKey")
    @ApiOperation(value = "修改记录")
    public Result updateByPrimaryKey(@RequestBody T record) {
        boolean flag = coreService.updateById(record);
        if (!flag) {
            log.error("更新记录：{}，失败！！！", record);
            return Result.error("更新记录失败！！！");
        }
        log.info("更新记录：{}，成功！！！", record);
        return Result.ok();
    }


    /**
     * 4.1，根据id查询
     *
     * @param id
     * @return
     */
    @Override
    @GetMapping("/findById/{id}")
    @ApiOperation(value = "根据id查询信息")
    public Result<T> findById(@PathVariable(name = "id") Serializable id) {
        T t = coreService.getById(id);
        return Result.ok(t);
    }

    /**
     * 4.2，查询所有数据
     *
     * @return
     */
    @Override
    @GetMapping("/findAll")
    @ApiOperation(value = "查询所有的信息")
    public Result<List<T>> findAll() {
        List<T> list = coreService.list();
        return Result.ok(list);
    }

    /**
     * 4.3，条件查询
     * 只能用等号方式来实现  select * from xxx where yyy=? and zzz=? and aaa=?
     * 获取泛型所在类，找到该类所有参数，循环便利，判断是否为空
     * TableField annotation = field.getAnnotation(TableField.class);
     * annotation.value()
     * 这两部分主要是获取该实体类上注解的值，用于条件判断
     *
     * @param record
     * @return
     */
    @Override
    @PostMapping("/listCondition")
    @ApiOperation(value = "条件查询")
    public Result<List<T>> findByRecord(@RequestBody T record) throws IllegalAccessException {
        QueryWrapper<T> queryWrapper = new QueryWrapper();
        Field[] fields = record.getClass().getDeclaredFields();
        for (Field field : fields) {
            TableField annotation = field.getAnnotation(TableField.class);
            try {
                field.setAccessible(true);
                Object value = field.get(record);
                if (value != null) {
                    //参数1 是列名 参数2 页面传递过来的值
                    queryWrapper.eq(annotation.value(), value);
                }
                if ("updateTime".equals(field.getName())) {
                    queryWrapper.orderByDesc("updateTime");
                }

            } catch (IllegalAccessException e) {
                log.error("条件查询错误！！！", e);
                throw e;
            }
        }
        List<T> list = coreService.list(queryWrapper);
        return Result.ok(list);
    }

    /**
     * 5，条件分页查询
     * select * from xxx where xxx=? and yyy like '%?%' limit 0,10
     *
     * @param pageRequestDto
     * @return
     */
    @PostMapping(value = "/findByPage")
    @Override
    @ApiOperation(value = "条件分页查询")
    public Result findByPage(@RequestBody PageRequestDto<T> pageRequestDto) throws IllegalAccessException, IntrospectionException, InvocationTargetException {
        log.info("请求参数为：{}", pageRequestDto);
        Page<T> page = new Page<>(pageRequestDto.getPage(), pageRequestDto.getSize());
        //条件 name 查询 非 lamda表达式查询条件
        QueryWrapper<T> queryWrapper = getWrapper(pageRequestDto.getBody());
        IPage<T> iPage = coreService.page(page, queryWrapper);
        return Result.successByPage(iPage.getCurrent(), iPage.getSize(), iPage.getTotal(), iPage.getPages(), iPage.getRecords());
    }

    private QueryWrapper<T> getWrapper(T body) throws IllegalAccessException, IntrospectionException, InvocationTargetException {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        if (body == null) {
            return queryWrapper;
        }
        Field[] declaredFields = body.getClass().getDeclaredFields();
        for (Field declaredField : declaredFields) {
            try {
                //遇到 id注解 则直接跳过 不允许实现根据主键查询
                //https://www.coder.work/article/2808807
                if (declaredField.isAnnotationPresent(TableId.class) || "id".equals(declaredField.getName())) {
                    //遇到
                    continue;
                }
                //属性描述器  record.getClass() javax.bean.BeanUtils
                PropertyDescriptor propDesc = new PropertyDescriptor(declaredField.getName(), body.getClass());
                //获取这个值  先获取读方法的方法对象,并调用获取里面的值  getXxx  setXxx
                Object value = propDesc.getReadMethod().invoke(body);
                //如果是字符串
                TableField annotation = declaredField.getAnnotation(TableField.class);
                //如果传递的值为空则不做处理
                if (value != null) {
                    //如是字符串 则用like
                    if (value.getClass().getName().equals("java.lang.String")) {
                        queryWrapper.like(annotation.value(), value);
                    } else {
                        //否则使用=号
                        queryWrapper.eq(annotation.value(), value);
                    }
                }

            } catch (Exception e) {
                log.error("分页查询错误！！！");
                throw e;
            }
        }
        return queryWrapper;
    }


}
